﻿/*****************************************************************//**
 * @file    FITKPartDataSetManager.h
 * @brief   The dataset manager of all parts.
 *  
 * @author  ChengHaotian (yeguangbaozi@foxmail.com)
 * @date    2024-12-11
 *********************************************************************/

#ifndef __FITKPARTDATASETMANAGER_H__
#define __FITKPARTDATASETMANAGER_H__

#include <QObject>

#include <QHash>
#include <QVariant>

// Forward declaration
class vtkDataSet;
class vtkUnstructuredGrid;
class vtkPolyData;

namespace Core
{
    class FITKAbstractDataObject;
}

namespace Interface
{
    class FITKGeometryMeshVS;
    class FITKVirtualTopoManager;
}

namespace Exchange
{
    /**
     * @brief   The struct for part geometry.
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-12-30
     */
    struct PartGeomDataVTK
    {
        // The dataset of the part geometry.
        vtkUnstructuredGrid* DataSetVertex = nullptr;
        vtkUnstructuredGrid* DataSetEdge = nullptr;
        vtkPolyData* DataSetFace = nullptr;

        // The geometry hash code.
        QVariant ShapeState = QVariant();

        // For picking.
        //@{
        // VTK -> Shape
        //@{
        // The id array for getting the vertex id of picked vertex cell.
        QVector<int> CellIdVertexIdMap;

        // The id array for getting the edge id of picked cell.
        QVector<int> CellIdEdgeIdMap;

        // The id array for getting the face id of picked cell.
        QVector<int> CellIdFaceIdMap;
        //@}

        // Shape -> Shape ( Find children )
        //@{
        // The ID hash for getting the solid id of the picked face cell.
        QHash<int, int> FaceSolidIdMap;
        //@}

        // Shape -> VTK
        //@{
        // The id array for getting the cell id with vertex id.
        // The key is the shape id of vertex in indexed map,
        // the values are the VTK cell id in vtkDataSet.
        QHash<int, int> VertexIdCellIdMap;

        // The id array for getting the cell id with edge id.
        // The key is the shape id of edge in indexed map,
        // the values are the VTK cell id in vtkDataSet.
        QHash<int, QVector<int>> EdgeIdCellIdsMap;

        // The face id and cell id map.
        // The key is the shape id of face in indexed map,
        // the values are the VTK cell ids in vtkDataSet.
        QHash<int, QVector<int>> FaceIdCellIdsHash;

        // The solid and face id map.
        // The key is the shape id of solid in indexed map,
        // the values are the shape face ids in indexed map.
        QHash<int, QVector<int>> SolidFaceIdsHash;
        //@}

        // VTK -> Data
        //@{
        // The id array for getting the sub-command id of the picked vertex cell.
        QVector<int> VertexCellIdCmdIdMap;

        // The id array for getting the sub-command id of the picked edge cell.
        QVector<int> EdgeCellIdCmdIdMap;

        // The id array for getting the sub-command id of the picked face( or solid ) cell.
        QVector<int> FaceCellIdCmdIdMap;
        //@}
        //@}
    };

    /**
     * @brief   The dataset manager of all parts.
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-12-11
     */
    class FITKPartDataSetManager : public QObject
    {
        Q_OBJECT
    public:
        /**
         * @brief   Get the instance of this class.[static]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        static FITKPartDataSetManager* getInstance();

        /**
         * @brief   Delete the instance.[static]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        static void Destory();

        /**
         * @brief   Get the part mesh dataset of the given part id.
         * @param   update: Update the dataset[default]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        vtkDataSet* getPartMeshDataSet(int partId, bool update = false);

        /**
         * @brief   Get the part geometry dataset of the given part id.
         * @param   type: The geometry dataset type( 0: Vertex, 1: Edge, 2: Face )
         * @param   update: Update( re-generate ) the dataset[default]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        vtkDataSet* getPartGeomDataSet(int partId, int type, bool update = false);

        /**
         * @brief   Get the part geometry dataset of the given part id.
         * @param   update: Update( re-generate ) the dataset[default]
         * @param   ioData: The returned part data[quote]
         * @param   update: Update( re-generate ) the dataset[default]
         * @return  Wether the part id is valid and the whether the part has valid geometry
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        bool getPartGeomData(int partId, PartGeomDataVTK* & ioData, bool update = false);

    private:
        /**
         * @brief   Constructure.
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        FITKPartDataSetManager() = default;

        /**
         * @brief   Desturcture.[virtual]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        virtual ~FITKPartDataSetManager();

        // Tool functions - Split shape data and save the id map.
        //@{
        /**
         * @brief   Create and add the shape's vertice grid data.
         * @param   meshVS: The tesselation data of the geometry
         * @param   iData: The input geometry part data
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        void addVertexGrid(Interface::FITKGeometryMeshVS* meshVS, PartGeomDataVTK* iData, int cmdId);

        /**
         * @brief   Create and add the shape's edge grid data.
         * @param   meshVS: The tesselation data of the geometry
         * @param   iData: The input geometry part data
         * @param   cmdId: The sub-command data id
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        void addEdgeGrid(Interface::FITKGeometryMeshVS* meshVS, PartGeomDataVTK* iData, int cmdId);

        /**
         * @brief   Create and add the shape's face grid data.
         * @param   meshVS: The tesselation data of the geometry
         * @param   iData: The input geometry part data
         * @param   cmdId: The sub-command data id
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        void addFaceGrid(Interface::FITKGeometryMeshVS* meshVS, PartGeomDataVTK* iData, int cmdId);

        /**
         * @brief   Create the shape's solid and face Id map.
         * @param   topoMgr: The topo manager of the geometry
         * @param   iData: The input geometry part data
         * @param   cmdId: The sub-command data id
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        void initializeSolidFaceMap(Interface::FITKVirtualTopoManager* topoMgr, PartGeomDataVTK* iData);

        /**
         * @brief   Calculate the polydata normals for all points.
         * @param   polyData: The polydata
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-19
         */
        void calculatePointNormals(vtkPolyData* polyData);
        //@}

        /**
         * @brief   Reset the vtk data object.[template]
         * @param   obj: The vtk data object.
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        template <class T>
        void resetVtkObj(T* obj)
        {
            if (obj)
            {
                obj->Reset();
            }
        }

        /**
         * @brief   Reset the vtk data object by copying a new one.[template]
         * @param   obj: The vtk data object.
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-18
         */
        template <class T>
        void copyEmptyVtkObj(T* obj)
        {
            if (obj)
            {
                obj->DeepCopy(vtkSmartPointer<T>::New());
            }
        }

    private slots:
        /**
         * @brief   Slot - For release the vtk datasets.
         * @param   objDel: The deleted object
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        void slot_partGeomDeleted(Core::FITKAbstractDataObject* objDel);

    private:
        /**
         * @brief   The instance of the class.[static]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        static FITKPartDataSetManager* s_instance;
        
        /**
         * @brief   The dict of the part data id and its geometry data.
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-12-11
         */
        QHash<int, PartGeomDataVTK*> m_partGeomDataHash;

    };
}   // namespace Exchange

#endif // __FITKPARTDATASETMANAGER_H__
